package a41;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.AnnotationMetadata;

import java.util.List;

public class A41_1 {

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.setAllowBeanDefinitionOverriding(false);   //同名Bean不允许覆盖。
        context.registerBean("config",Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.refresh();
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean1.class));
    }

    /*
    @Import({AutoConfiguration1.class, AutoConfiguration2.class})
    static class Config{

    }
     */

    @Configuration //本项目的配置类
    @Import(MyImportSelector.class)
    static class Config{
        @Bean
        public Bean1 bean1() {
            return new Bean1("本项目");
        }
    }

    /**
     * Import注解用来导入配置类。如果@import导入的是ImportSelector的实现类，其中的selectImports返回的类
     * 会被导入容器中。这样设计与什么好处呢？如果有很多个配置类，只需要在ImportSelector统一返回就行。实际上配置类都通过
     * key-多个value的形式配置在META_INF下spring.factories的文件中。而ImportSelector只需要读取响应的key来获取
     * 对应的配置类，统一返回，就可以同时导入很多个配置类呢。
     */
    static class MyImportSelector implements DeferredImportSelector { //相比ImportSelector，DeferredImportSelector会推迟其Bean的注入.放在Bean项目的Bean注入之后注入。

        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            //return new String[]{AutoConfiguration1.class.getName(), AutoConfiguration2.class.getName()};

            //读取spring.factories里配置的配置类返回
            List<String> names = SpringFactoriesLoader.loadFactoryNames(MyImportSelector.class, null);


            /*
            List<String> names2 = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, null);
            for (String name : names2) {
                System.out.println(name);
            }
             */

            return names.toArray(new String[0]);
        }
    }


    @Configuration // 第三方的配置类
    static class AutoConfiguration1 {
        @ConditionalOnMissingBean  //如果容器没有同名Bean才注入改Bean，有则不注入
        @Bean
        public Bean1 bean1() {
            return new Bean1("第三方");
        }
    }

    static class Bean1 {
        private String name;

        public Bean1() {
        }

        public Bean1(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Bean1{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }




    @Configuration // 第三方的配置类
    static class AutoConfiguration2 {
        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

    static class Bean2 {

    }
}
